package com.ftp.longdistance.ftpmapper;
import java.io.*;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.List;


import cn.hutool.core.io.IoUtil;
import com.ftp.longdistance.annotation.FileType;
import com.ftp.longdistance.bean.Ftp;

import com.ftp.longdistance.exception.BizException;
import com.ftp.longdistance.ftpmapper.service.PointOfJunction;
import com.ftp.longdistance.util.FileViewUtils;
import com.ftp.longdistance.util.PathUtils;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.net.ftp.*;

import org.springframework.web.multipart.MultipartFile;


import javax.servlet.http.HttpServletResponse;

/**
 * @author TanYongPeng
 * <p>
 *     Ftp模式
 * </p>
 */
@FileType(value = "FTP")
@Slf4j
public enum FtpFile implements PointOfJunction {
    /**
     * 当前类自己
     * 通过枚举来实现单例模式，不仅避免多线程同步问题，
     * 而且还能防止反序列化创建新的对象
     */
    INSTANCE;


    /**
     * //本地字符编码
     */
    static String LOCAL_CHARSET = "GBK";

    /**
     * // FTP协议里面，规定文件名编码为iso-8859-1
     */
    static String SERVER_CHARSET = "ISO-8859-1";

    private static FTPClient ftpClient = null;

    @Override
    public void logout(){
        if (ftpClient != null) {
            if (ftpClient.isConnected()) {
                try {
                    ftpClient.disconnect();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 配置连接
     * @return
     */
    @Override
    public boolean getConnect(Ftp ftp) {


        try {
            ftpClient = new FTPClient();
            /**
             * // 连接FTP服务器s
             */
            ftpClient.connect(ftp.getFtpHost(), ftp.getPort());
            /**
             * // 登陆FTP服务器
             */

            ftpClient.login(ftp.getUserName(), ftp.getPwd());
            if (!FTPReply.isPositiveCompletion(ftpClient.getReplyCode())) {

                return false;
            } else {
                log.info("FTP连接成功。");
                return true;
            }
        } catch (SocketException e) {

            return false;
        } catch (IOException e) {
            return false;
        }
    }


    /**
     * 下载
     * @param serverPath
     * @param fileName
     */
    @Override
    public void download(String serverPath,String fileName) {
        try {
            ftpClient.setControlEncoding("UTF-8");
            ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
            ftpClient.enterLocalPassiveMode();
            ftpClient.changeWorkingDirectory(new String(serverPath.getBytes("GBK"),"iso-8859-1"));
            String path = PathUtils.viewPath(fileName);
            File file = new File(path);
            if (file.exists()) {
                fileName = "("+System.currentTimeMillis()+")"+fileName;
                File file2 = new File(PathUtils.viewPath(fileName));
                download(file2,fileName);
            }else {
                download(file,fileName);
            }
        } catch (FileNotFoundException e) {
            throw new BizException("103","文件下载异常");
        } catch (SocketException e) {
            throw new BizException("103","文件下载异常");
        } catch (IOException e) {
            throw new BizException("103","文件下载异常");
        }
    }

    @Override
    public void fileView(HttpServletResponse response, String path, String fileName) {

        try {
            ftpClient.setControlEncoding("UTF-8");
            ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
            ftpClient.enterLocalPassiveMode();
            ftpClient.changeWorkingDirectory(new String(path.getBytes("GBK"),"iso-8859-1"));
            String fileStr = PathUtils.fileViewPath(fileName);
            File file = new File(fileStr);
            if (file.exists()){
                file.delete();
            }
            download(file,fileName);
            FileViewUtils.fileView(response,file);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }



    private void download(File file,String fileName) throws IOException {
        OutputStream os = new FileOutputStream(file);
        //复制文件流
        boolean flag2 = ftpClient.retrieveFile(new String(fileName.getBytes("GBK"),"iso-8859-1"), os);
        if (!flag2) {
            log.error("没有找到" + fileName + "---该文件");
            file.delete();
        }
        IoUtil.close(os);
    }

    /**
     * 文件上传
     * @param ftpPath
     * @param file
     */
    @Override
    public void upload(String ftpPath, MultipartFile file) {
        try {
            ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
            // 用被动模式传输,解决linux服务长时间等待，导致超时问题
            ftpClient.enterLocalPassiveMode();
            // 设置默认超时时间
            ftpClient.setDefaultTimeout(30000);
            //设置缓存区，默认缓冲区大小是1024，也就是1K
            ftpClient.setBufferSize(1024*1024);
            if (FTPReply.isPositiveCompletion(ftpClient.sendCommand("OPTS UTF8", "ON"))){
                LOCAL_CHARSET = "UTF-8";
            }
            //中文支持
            ftpClient.setControlEncoding(LOCAL_CHARSET);
            //切换目录，目录不存在创建目录
            boolean chagenDirFlag=ftpClient.changeWorkingDirectory(ftpPath);
            if(!chagenDirFlag){
                ftpClient.makeDirectory(ftpPath);
                ftpClient.changeWorkingDirectory(ftpPath);
            }
            //上传至Ftp
            ftpClient.storeFile(new String(file.getOriginalFilename().getBytes(LOCAL_CHARSET),
                    SERVER_CHARSET), file.getInputStream());
        } catch (FileNotFoundException e) {
            throw new BizException();
        } catch (SocketException e) {
            throw new BizException();
        } catch (IOException e) {
            throw new BizException();
        }
    }

    /**
     * 创建文件夹
     * @param path
     */
    @Override
    public void dir(String path){
        ftpClient.setControlEncoding(LOCAL_CHARSET);
        try {
            ftpClient.makeDirectory(path);
        } catch (IOException e) {
            throw new BizException("105","-bash: "+path+": command execution failure  文件创建失败");
        }
    }

    /**
     * 删除文件夹
     * @param path
     */
    @Override
    public void deleteDir(String path){
        try {
            ftpClient.removeDirectory(path);
        } catch (IOException e) {
            throw new BizException("105","-bash: "+path+": command execution failure  文件夹删除失败");
        }
    }

    /**
     * 删除
     * @param ftpPath 服务器地址
     * @param ftpFileName 服务器文件名
     * @return
     */
    @Override
    public void delete(String ftpPath,String ftpFileName) {
        // 中文支持
        ftpClient.setControlEncoding("UTF-8");
        try {
            ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
            // 用被动模式传输,解决linux服务长时间等待，导致超时问题
            ftpClient.enterLocalPassiveMode();
            // 设置默认超时时间
            ftpClient.setDefaultTimeout(30000);
            //切换目录，目录不存在创建目录
            ftpClient.changeWorkingDirectory(ftpPath);
            ftpClient.deleteFile(ftpFileName);
        } catch (SocketException e) {
            throw new BizException("104","文件删除异常");
        } catch (IOException e) {
            throw new BizException("104","文件删除异常");
        }
    }


    /**
     * 遍历当前文件下文件夹和文件
     * @param ftpPath 服务器地址(后面得加 ' / ')
     * @return
     */
    @Override
    public List<String> listFiles(String ftpPath){
        List<String> arFiles = new ArrayList<>();
        ftpClient.setControlEncoding("UTF-8");
        if(ftpPath.startsWith("/")&&ftpPath.endsWith("/")){
            //更换目录到当前目录
            try {
                boolean b = ftpClient.changeWorkingDirectory(ftpPath);
                if (b){
                    FTPFile[] files = ftpClient.listFiles();
                    //遍历文件夹下所有文件
                    for(FTPFile file:files){
                        arFiles.add(file.getName());
                    }
                }else {
                    return null;
                }

            } catch (IOException e) {
                throw new BizException("101","文件路径异常");
            }
        }
        return arFiles;
    }

    @Override
    public boolean checkExist(String path){
        return checkFileName(path);
    }

    @Override
    public boolean checkFileName(String path){
        try {
            boolean b = ftpClient.changeWorkingDirectory(path);
            if (b){
                ftpClient.changeWorkingDirectory("..");
            }
            return b;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;
    }




    /**
     * 改名
     * @param oldPath 服务器地址加文件名
     * @param newPath 新的名称
     * @return
     */
    @Override
    public void  rename(String oldPath,String newPath){
        try {
            ftpClient.rename(oldPath,newPath);
        } catch (IOException e) {
            throw new BizException("107","文件名更改异常");
        }
    }

    @Override
    public String fileAuthority(String path) {
        return "获取失败";
    }


    /**
     * 获取文件大小
     * @param path
     * @return
     */
    @Override
    public String fileSize(String path){
        boolean b = false;
        String fileSize = "";
        try {
            b = ftpClient.changeWorkingDirectory(PathUtils.split(path)[0]);
            if (b){
                FTPFile[] files = ftpClient.listFiles();
                //遍历文件夹下所有文件
                for(FTPFile file:files){
                    if (file.getName().equals(PathUtils.split(path)[1])){
                        fileSize = String.valueOf(file.getSize());
                        break;
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return fileSize;
    }

}
